import os
import struct

OUTPUT      = "output"
IMG         = "./output/a.img"
BOOT_SRC    = "./bootloader/boot.asm"
BOOT_BIN    = "./output/boot.bin"
LOADER_SRC  = "./bootloader/loader.asm"
LOADER_BIN  = "./output/loader.bin"
KENTRY_SRC  = "./init/kentry.asm"
KENTRY_O    = "./output/kentry.o"
MAIN_SRC    = "./init/main.c"
MAIN_O      = "./output/main.o"
KERNEL_OUT  = "./output/kernel.out"
KERNEL_BIN  = "./output/kernel.bin"



def main():
    # 创建文件夹 output
    if not os.path.exists(OUTPUT):
        os.mkdir(OUTPUT)

    # 编译 boot.asm
    src = BOOT_SRC
    out = BOOT_BIN
    cmd_str = "nasm " + src + " -o " + out
    print(cmd_str)
    os.system(cmd_str)

    # 编译 loader.asm
    src = LOADER_SRC
    out = LOADER_BIN
    cmd_str = "nasm " + src + " -o " + out
    print(cmd_str)
    os.system(cmd_str)

    # 获取 loader.bin 所占扇区数
    stats = os.stat(LOADER_BIN)
    loader_blocks = int(stats.st_size / 512) + 1 

    # 编译 kentry.asm
    # nasm -f elf32 kentry.asm -o kentry.o
    src = KENTRY_SRC
    out = KENTRY_O
    cmd_str = "nasm -f elf32 " + src + " -o " + out
    print(cmd_str)
    os.system(cmd_str)

    # 编译 main.c
    # gcc -m32 -nostdinc -c main.c -o main.o
    src = MAIN_SRC
    out = MAIN_O
    cmd_str = "gcc -m32 -nostdinc -c " + src + " -o " + out
    print(cmd_str)
    os.system(cmd_str)

    # 链接 kernel
    # ld -Ttext 0xB000 -s -m elf_i386 -o kernel.out  kentry.o main.o
    src = KENTRY_O + " " + MAIN_O
    out = KERNEL_OUT
    cmd_str = "ld -Ttext 0xB000 -s -m elf_i386 -o " + out + " " + src
    print(cmd_str)
    os.system(cmd_str)

    # 将 kernel.out 转为 kernel.bin
    # objcopy -O binary kernel.out kernel.bin
    src = KERNEL_OUT
    out = KERNEL_BIN
    cmd_str = "objcopy -O binary " + src + " " + out
    print(cmd_str)
    os.system(cmd_str)

     # 获取 kernel.bin 所占扇区数
    stats = os.stat(KERNEL_BIN)
    kernel_blocks = int(stats.st_size / 512) + 1 

    # 创建一个 60M 的虚拟硬盘，由于搭了两套开发环境，所以这里 bximage 有两种命令格式
    # 使用 “bximage --help” 命令可获得 bximage 的用法
    # 另一个：bximage $@ -func="create" -hd=60 -imgmode="flat" -q
    # 自动计算虚拟硬盘大小，单位 M
    hard_size = int(os.stat(KERNEL_BIN).st_size/1024/1024) + 2
    cmd_str = "bximage " + IMG + ' -hd -size=' + str(hard_size) + ' -mode="flat" -q'
    print(cmd_str)
    os.system(cmd_str)

    # 将 boot.bin 写入硬盘 a.img 的扇区 0
    cmd_str = "dd if=" + BOOT_BIN + " of=" + IMG + " bs=512 count=1 conv=notrunc"
    print(cmd_str)
    os.system(cmd_str)

	# 将 loader.bin 写入硬盘 a.img 的扇区 2
    cmd_str = "dd if=" + LOADER_BIN + " of=" + IMG + " bs=512 count=" + str(loader_blocks) + " seek=2 conv=notrunc"
    print(cmd_str)
    os.system(cmd_str)

	# 将 kernel.bin 写入硬盘 a.img 的扇区 3
    # cmd_str = "dd if=" + KERNEL_BIN + " of=" + IMG + " bs=512 count=" + str(kernel_blocks) + " seek=3 conv=notrunc"
    cmd_str = "dd if=" + KERNEL_BIN + " of=" + IMG + " bs=512 count=" + str(kernel_blocks) + " seek=" + str(2+loader_blocks) + " conv=notrunc"
    print(cmd_str)
    os.system(cmd_str)


    # 读取 IMG 文件，将 loader.bin 所占扇区数写到扇区 1 的前两个字节中；将 kernel.bin 所占扇区数写到扇区 1 的第 3-4 字节中
    img = []
    with open(IMG, "rb") as f:
        data = f.read()
        for i in range(len(data)):
            img.append(data[i])
        img[512] = loader_blocks
        img[513] = loader_blocks>>8
        img[514] = kernel_blocks
        img[515] = kernel_blocks>>8
    with open(IMG, 'wb') as f:  
        for x in img:
            f.write(struct.pack('B', x))

    print("Success!")


if __name__ == '__main__':
    main()